package mainPackage;

import Memmory.Word;
import gui.*;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFileChooser;

public class main {
    private static final String osURI = "D:/Programavimas/JAVA/OS/src/asm programs/operatingsystem.os";
    //private static final String osURI = "C:\\Users\\Admin\\Documents\\NetBeansProjects\\vu-os-project\\src\\mainPackage\\operatingsystem.os";

    private static Thread thread, stepThread;
    private static boolean restartState = false;
    
    private static int cmdExecutingTime = 50;
    
    static GUI gui = new GUI();
    static RealMachine RM;
    
    public static void performStep() {
        
        if (stepThread != null && !stepThread.isAlive()) {
            stepThread = null;
        }
        
        if(stepThread == null) {
            stepThread = new Thread() {
                @Override
                public void run() {
                    RM.performStep();
                    drawRegisters();
                    drawMemmory();
                }
            };
            stepThread.start();
        }
    }
    
    public static void executeProgram() {
        
        if (thread != null && !thread.isAlive()) {
            thread = null;
        }
        
        if (thread == null) {
            thread = new Thread() {
                public void run() {
                    try {
                        while (!restartState) {
                            RM.performStep();
                            Thread.sleep(cmdExecutingTime);
                            drawRegisters();
                            drawMemmory();
                        }
                        restartState = false;
                    } catch (Exception e) {
                    }

                }
            };
            thread.start();
        }
    }
    
    public static void drawRegisters() {
            gui.regPTR.setText(Integer.toString(RM.PTR.getNumber()));
            gui.regIC.setText("(" + Integer.toString(RM.IC[0]) + ", " + Integer.toString(RM.IC[1]) + ")");
            gui.regA.setText(Integer.toString(RM.A.getNumber()));
            gui.regB.setText(Integer.toString(RM.B.getNumber()));
            gui.regL.setText(Integer.toString(RM.L));
            gui.regMODE.setText(Character.toString((char) RM.MODE));
            gui.regSI.setText(Integer.toString(RM.SI));
            gui.regPI.setText(Integer.toString(RM.PI));
            gui.regTI.setText(Integer.toString(RM.TI));
            gui.regIOI.setText(Integer.toString(RM.IOI));
            gui.regTIMER.setText(Integer.toString(RM.TIMER));
            gui.regCH1.setText(Integer.toString(RM.CH1));
            gui.regCH2.setText(Integer.toString(RM.CH2));
            gui.regCH3.setText(Integer.toString(RM.CH3));
    }
    
    public static void drawMemmory() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                gui.memmoryTableModel.setRowCount(0);
                gui.virtualMemmoryTableModel.setRowCount(0);
                for (int i = 0; i < RealMachine.BLOCK_COUNT * RealMachine.BLOCK_SIZE; i++) {
                    Word w = RM.MEMMORY.getWord(i);
                    byte[] wordBytes = w.getBytes();
                    String address = "(" + (i / RealMachine.BLOCK_SIZE) + ", " + (i % RealMachine.BLOCK_SIZE) + ")";
                    gui.memmoryTableModel.addRow(new Object[]{address, wordBytes[0],wordBytes[1], wordBytes[2], wordBytes[3]});
                }
                if (RM.VM != null) {
                    for (int i = 0; i < RealMachine.VM_BLOCK_COUNT * RealMachine.BLOCK_SIZE; i++) {
                        Word w = RM.VM.virtualMemmory.getWord(i);
                        byte[] wordBytes = w.getBytes();
                        String address = "(" + (i / RealMachine.BLOCK_SIZE) + ", " + (i % RealMachine.BLOCK_SIZE) + ")";
                        gui.virtualMemmoryTableModel.addRow(new Object[]{address, wordBytes[0],wordBytes[1], wordBytes[2], wordBytes[3]});
                    }
                }
                if (RM.VM != null && RM.MODE == 'V') {
                    int rowIndex = RM.IC[0] * RealMachine.BLOCK_SIZE + RM.IC[1];
                    gui.virtualMemmoryTable.setRowSelectionInterval(rowIndex, rowIndex);
                    gui.virtualMemmoryTable.scrollRectToVisible(new Rectangle(gui.virtualMemmoryTable.getCellRect(rowIndex, 0, true)));
                }

                if (RM.MODE == 'S') {
                    int rowIndex = RM.IC[0] * RealMachine.BLOCK_SIZE + RM.IC[1];
                    gui.memmoryTable.setRowSelectionInterval(rowIndex, rowIndex);
                    gui.memmoryTable.scrollRectToVisible(new Rectangle(gui.memmoryTable.getCellRect(rowIndex, 0, true)));
                }
            }
        });
    }
    
    public static void loadProgram(String uri) throws Exception {
        RM.createVirtualMachine(3, uri);
        RM.activateVirtualMachine(3);
        drawMemmory();
        drawRegisters();
    }

    public static void main(String[] args) throws Exception {
        RM = new RealMachine(gui.console, osURI);
        
        drawMemmory();
        drawRegisters();
        
        gui.stepButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                performStep();
            }
        });
        
        gui.executeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    executeProgram();
                } catch (Exception ex) {
                }
            }
        });
        
        gui.loadButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //loadProgram("C:\\Users\\Admin\\Documents\\NetBeansProjects\\vu-os-project\\src\\mainPackage\\testProg_1.prog");
                    //loadProgram("E:/Programavimas/JAVA/OS/src/mainPackage/interval.prog");
                } catch(Exception ex) {}
                JFileChooser jfc = new JFileChooser();
                jfc.showOpenDialog(jfc);
                if (jfc.getSelectedFile() != null) {
                    try {
                        loadProgram(jfc.getSelectedFile().getAbsolutePath());
                    } catch (Exception ex) {
                    }
                    
                }
            }
        });
        
        gui.restartProcessorButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    restartState = true;
                    gui.console.mustRestart = true;
                    RM.restart();
                    drawMemmory();
                    drawRegisters();
                } catch (Exception ex) {
                }
            }
        });
        
        gui.setVisible(true);
    }
}
